package com.chenfan.mcn.component;

import com.chenfan.common.vo.Response;
import com.chenfan.mcn.annotations.ApiResultWrapper;
import com.chenfan.mcn.clients.baseinfo.BaseInfoClient;
import com.chenfan.mcn.clients.baseinfo.DescByCodeDTO;
import com.chenfan.common.extension.dict.DictTranslationUtils;
import com.chenfan.common.extension.dict.annotation.DictTranslation;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.mcn.extension.Res;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.stereotype.Component;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;

import java.io.IOException;
import java.util.*;

/**
 *  Api接口返回值处理
 * @author wulg
 * @date 2021-07-30
 **/
@Component
public class ApiReturnValueHandler implements HandlerMethodReturnValueHandler, InitializingBean {

    @Autowired
    private RequestMappingHandlerAdapter adapter;

    @Autowired
    private BaseInfoClient baseInfoClient;

    private RequestResponseBodyMethodProcessor processor;

    @Override
    public void afterPropertiesSet() {
        List<HandlerMethodReturnValueHandler> unmodifiableList = adapter.getReturnValueHandlers();
        List<HandlerMethodReturnValueHandler> list = new ArrayList<>(unmodifiableList.size());
        for (HandlerMethodReturnValueHandler returnValueHandler : unmodifiableList) {
            if (returnValueHandler instanceof RequestResponseBodyMethodProcessor) {
                this.processor = (RequestResponseBodyMethodProcessor) returnValueHandler;
                list.add(this);
            } else {
                list.add(returnValueHandler);
            }
        }
        adapter.setReturnValueHandlers(list);
    }

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return processor.supportsReturnType(returnType);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
                                  ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

        this.dictTranslationIfNecessary(returnValue, returnType);
        processor.handleReturnValue(
                wrapApiResultIfNecessary(returnValue, returnType),
                returnType,
                mavContainer,
                webRequest);
    }

    /**
     * 如果需要则翻译字典
     * @param returnValue
     * @param returnType
     */
    private void dictTranslationIfNecessary(Object returnValue, MethodParameter returnType) {
        if(returnValue == null || !returnType.getMethod().isAnnotationPresent(DictTranslation.class)) {
            return;
        }
        boolean needTranslation = true;
        if(returnValue instanceof Res)  {
            Res<Object> res = (Res<Object>)returnValue;
            needTranslation = res.getCode() == McnErrorCode.SUCCESS.code() || res.getCode() == McnErrorCode.SUCCESS_OLD.code();
        }
        if(needTranslation) {
            DictTranslationUtils.translation(returnValue,
                    (dictProfileList, dictList) -> Objects.requireNonNull(baseInfoClient.getDescByCode(new DescByCodeDTO()
                            .setDictsCodes(dictList).setProfileCodes(dictProfileList))).getObj());
        }
    }

    /**
     * 如果需要则封装API返回结果
     * @param returnValue
     * @param returnType
     * @return
     */
    private Object wrapApiResultIfNecessary(Object returnValue, MethodParameter returnType) {
        Class<?> controllerClass = returnType.getContainingClass();
        if (controllerClass.isAnnotationPresent(ApiResultWrapper.class) || returnType.hasMethodAnnotation(ApiResultWrapper.class)) {
            //如果接口返回值已被Response&子类Res封装了，则不做处理 兼容老的Response
            Class<?> returnClass = returnType.getMethod().getReturnType();
            if(!Response.class.isAssignableFrom(returnClass)) {
                return Res.ok(returnValue);
            }
        }
        return returnValue;
    }
}
